package mc.support.service.common.impl;

import com.taobao.api.ApiException;
import com.taobao.api.DefaultTaobaoClient;
import com.taobao.api.TaobaoClient;
import com.taobao.api.domain.*;
import com.taobao.api.request.ItemRecommendAddRequest;
import com.taobao.api.request.ItemRecommendDeleteRequest;
import com.taobao.api.response.*;
import mc.support.config.TaobaoClientConfig;
import mc.support.service.common.ITaobaoTopAPIService;
import mc.support.support.pojo.Fragment;
import mc.support.taobao.api.*;
import mc.support.taobao.api.comm.TaobaoClientWrapper;
import mc.support.taobao.api.fields.*;
import mc.support.util.PlainUtil;
import mc.support.util.SliceUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created with IntelliJ IDEA. <br/>
 * User: francis    <br/>
 * Date: 13-11-20    <br/>
 * Time: 17:18  <br/>
 */
public class TaobaoTopAPIServiceImpl implements ITaobaoTopAPIService {

    private TaobaoClientConfig clientConfig;
    private volatile TaobaoClient taobaoClient;

    private OnSaleItemFetcher onSaleItemFetcher = new OnSaleItemFetcher();
    private InventoryItemFetcher inventoryItemFetcher = new InventoryItemFetcher();
    private ItemsFetcher itemsFetcher = new ItemsFetcher();
    private ItemFetcher itemFetcher = new ItemFetcher();
    private SellerCatsFetcher sellerCatsFetcher = new SellerCatsFetcher();
    private ItemUpdater itemUpdater = new ItemUpdater();
    private CloudDataFetcher cloudDataFetcher = new CloudDataFetcher();
    private CloudDataStatusFetcher cloudDataStatusFetcher = new CloudDataStatusFetcher();
    private ShopInfoFetcher shopInfoFetcher = new ShopInfoFetcher();
    private VasSubscribeGetFetcher vasSubscribeGetFetcher = new VasSubscribeGetFetcher();
    private VasOrderSearchFetcher vasOrderSearchFetcher = new VasOrderSearchFetcher();
    private ItemsListFetcher itemsListFetcher = new ItemsListFetcher();
    private ItemCatsFetcher itemCatsFetcher = new ItemCatsFetcher();
    private ShopRemainShowcaseFetcher shopRemainShowcaseFetcher = new ShopRemainShowcaseFetcher();
    private SellerFetcher sellerFetcher = new SellerFetcher();
    private BrandFetcher brandFetcher = new BrandFetcher();
    private JushitaJdpUserAdder jushitaJdpUserAdder = new JushitaJdpUserAdder();
    private CloudDataFlowbacker cloudDataFlowbacker = new CloudDataFlowbacker();
    private MsgFetcher msgFetcher = new MsgFetcher();
    private ItemPropsFetcher itemPropsFetcher = new ItemPropsFetcher();
    private SaleLinkGenerator saleLinkGenerator = new SaleLinkGenerator();
    private UsersFetcher usersFetcher = new UsersFetcher();
    private DeliveryTemplateFetcher deliveryTemplateFetcher = new DeliveryTemplateFetcher();
    private ItemDelistingFetcher itemDelistingFetcher = new ItemDelistingFetcher();
    private ItemListingFetcher itemListingFetcher = new ItemListingFetcher();
    private ItemSkuFetcher itemSkuFetcher = new ItemSkuFetcher();
    private ItemDeleteFetcher itemDeleteFetcher = new ItemDeleteFetcher();
    private ItemProcessWarnsFetcher itemProcessWarnsFetcher = new ItemProcessWarnsFetcher();
    private ItemProcessPunishesFetcher itemProcessPunishesFetcher = new ItemProcessPunishesFetcher();
    private ItemProcessShieldsFetcher itemProcessShieldsFetcher = new ItemProcessShieldsFetcher();
    private ItemProcessAdvisesFetcher itemProcessAdvisesFetcher = new ItemProcessAdvisesFetcher();

    public void setClientConfig( TaobaoClientConfig clientConfig ) {
        this.clientConfig = clientConfig;
    }

    public TaobaoClientConfig getClientConfig() {
        return clientConfig;
    }

    @Override
    public List<Item> getOnSaleItems( String sessionKey, GetOnSaleItemFields fields ) {
        return onSaleItemFetcher.fetchOnSaleItems( sessionKey, fields, 0, 2 );
    }

    @Override
    public List<Item> getOnSaleItems( String sessionKey, GetOnSaleItemReq req ) {
        return onSaleItemFetcher.fetchOnSaleItems( sessionKey, req, 0, 2 );
    }

    @Override
    public List<Item> getInventoryItems( String sessionKey, GetInventoryItemReq req, GetInventoryItemFields fields ) {
        return inventoryItemFetcher.fetchItems( sessionKey, req, fields, 0, 2 );
    }

    @Override
    public List<Item> getInventoryItems( String sessionKey, GetInventoryItemFields fields ) {
        return inventoryItemFetcher.fetchItems( sessionKey, null, fields, 0, 2 );
    }

    @Override
    public Fragment<Item> getOnSaleItemsLimit( String sessionKey, GetOnSaleItemFields fields,
                                               int begin, int offset ) {
        return onSaleItemFetcher.fetchOnSaleItemsLimit( sessionKey, fields, 0, 2, begin, offset );
    }

    @Override
    public Fragment<Item> getInventoryItemsLimit( String sessionKey, GetInventoryItemReq req, GetInventoryItemFields fields, int begin, int offset ) {
        return inventoryItemFetcher.fetchItemsLimit( sessionKey, req, fields, begin, offset, 0, 2 );
    }

    @Override
    public Fragment<Item> getInventoryItemsLimit( String sessionKey, GetInventoryItemFields fields,
                                                  int begin, int offset ) {
        return inventoryItemFetcher.fetchItemsLimit( sessionKey, null, fields, begin, offset, 0, 2 );
    }

    @Override
    public Long getOnSaleItemCount( String sessionKey ) {
        return onSaleItemFetcher.getOnSaleItemsCount( sessionKey, 0, 2 );
    }

    /**
     * corresponding to "taobao.items.get"
     */
    @Override
    public List<Item> getItems( String sessionKey, String nick, GetItemsFields fields ) {
        return itemsFetcher.fetchItems( sessionKey, nick, fields, 0, 2 );
    }

    @Override
    public List<Item> getItemsByCat( String sessionKey, Long cid, GetItemsFields fields, Integer limit ) {
        return itemsFetcher.fetchItemsByCat( sessionKey, cid, fields, limit, 0, 2 );
    }

    @Override
    public Fragment<Item> getItemsLimit( String sessionKey, String nick, GetItemsFields fields,
                                         int begin, int offset ) {
        return itemsFetcher.fetchItemsLimit( sessionKey, nick, fields, 0, 2, begin, offset );
    }

    /**
     * corresponding to "taobao.item.get"
     */
    @Override
    public Item getItem( String sessionKey, Long itemId, GetItemInfoFields fields ) {
        return itemFetcher.fetchItem( sessionKey, itemId, fields, 0, 2 );
    }

    /**
     * corresponding to "taobao.items.get"
     */
    @Override
    public List<Item> searchItems( String sessionKey, String query, GetItemsFields fields,
                                   int begin, int offset ) {
        return itemsFetcher.searchItems( sessionKey, query, fields, 0, 2, begin, offset );
    }

    @Override
    public List<Item> searchItemsByPop( String sessionKey, GetItemsFields fields, long cid,
                                        String order, String props, int limit ) {
        return itemsFetcher.searchItemsByPopularity( sessionKey, fields, cid, order, props, limit );
    }

    /**
     * corresponding to "taobao.items.list.get" <br/>
     */
    @Override
    public List<Item> getItemsList( String sessionKey, Set<Long> itemIds, GetItemsListFields fields ) {
        Set<String> itemIdSet = PlainUtil.toStringSet( itemIds );
        int len = itemIdSet.size();
        List<Item> items = new ArrayList<Item>();
        //number of item is limit by 20 once.
        if ( len > 20 ) {
            List<String> total = new ArrayList<String>( itemIdSet );
            List<String> slice = null;
            int begin = 0;
            final int offset = 20;
            while ( true ) {
                slice = SliceUtil.doSlice( total, begin, offset - 1 );
                if ( null == slice || 0 == slice.size() ) {
                    break;
                }
                List<Item> tmp = itemsListFetcher.fetch( sessionKey,
                        new HashSet<>( slice ), fields, 0, 2 );
                if ( null != tmp ) {
                    items.addAll( tmp );
                }
                begin += offset;
            }
        } else {
            items.addAll( itemsListFetcher.fetch( sessionKey,
                    new HashSet<>( itemIdSet ), fields, 0, 2 ) );
        }

        return items;
    }

    @Override
    public List<SellerCat> getSellerCats( String sessionKey, String nick ) {
        return sellerCatsFetcher.fetchSellerCats( sessionKey, nick, 0, 2 );
    }

    /**
     * corresponding to "taobao.item.update"
     */
    @Override
    public ItemUpdateResponse updateItem( UpdateItemReq req ) {
        return itemUpdater.update( req, 0, 2 );
    }

    @Override
    public ItemUpdateResponse updateItemNoExcepHandle( UpdateItemReq req ) throws ApiException {
        return itemUpdater.updateNoExcepHandle( req, 0, 2 );
    }

    @Override
    public ShopRemainshowcaseGetResponse getShopRemainshowcase( String sessionKey ) throws ApiException {
        return shopRemainShowcaseFetcher.fetch( sessionKey, 0, 2 );
    }

    /**
     * corresponding to "taobao.shop.get"
     */
    @Override
    public Shop getShopInfo( String sessionKey, String nick, GetShopInfoFields fields ) {
        return shopInfoFetcher.fetch( sessionKey, nick, fields, 0, 2 );
    }

    /**
     * corresponding to "taobao.vas.subsc.searcht"
     */
    @Override
    public List<ArticleUserSubscribe> getArticleUserSubscribe( GetVasSubscribeReq req ) {
        return vasSubscribeGetFetcher.fetch( req, 0, 2 );
    }


    /**
     * corresponding to "taobao.user.seller.get"
     *
     * @param sessionKey
     * @param req
     * @return
     */
    @Override
    public User getSeller( String sessionKey, GetSellerReq req ) {
        return sellerFetcher.fetch( sessionKey, req, 0, 2 );
    }

    /**
     * corresponding to "taobao.itemcats.get"
     */
    @Override
    public List<ItemCat> getItemCats( String sessionKey, GetItemCatsReq req ) {
        return itemCatsFetcher.fetch( sessionKey, req, 0, 2 );
    }

    @Override
    public ClouddataMbpDataGetResponse mbpDataGet( GetCloudDataReq req ) {
        return cloudDataFetcher.mbpGet( req, 0, 2 );
    }

    /**
     * corresponding to "taobao.item.recommend.add"
     *
     * @throws ApiException
     */
    @Override
    public ItemRecommendAddResponse itemRecommendAdd( Long itemId, String sessionKey ) throws ApiException {
        return shopRemainShowcaseFetcher.itemRecommendAdd( itemId, sessionKey, 0, 2 );
    }

    /**
     * corresponding to "taobao.item.recommend.delete"
     *
     * @throws ApiException
     */
    @Override
    public ItemRecommendDeleteResponse itemRecommendDelete( Long itemId, String sessionKey ) throws ApiException {
        return shopRemainShowcaseFetcher.itemRecommendDelete( itemId, sessionKey, 0, 2 );
    }

    /**
     * @author kane
     */
    @Override
    public ItempropsGetResponse getBrandInfoByCid( Long cid,
                                                   GetBrandInfoFields fields ) {
        return brandFetcher.fetch( cid, fields );
    }

    @Override
    public Boolean addJushitaJdpUser( String sessionKey, String rdsName ) {
        return jushitaJdpUserAdder.add( sessionKey, rdsName, 0, 2 );
    }

    @Override
    public ClouddataMbpDataFlowbackResponse mbpDataFlowback( String sessionKey, String tableName, String data ) {
        return cloudDataFlowbacker.flowback( sessionKey, tableName, data, 0, 2 );
    }


    @Override
    public boolean permitUserOnMsg( String sessionKey ) {
        return msgFetcher.permitUserOnMsg( sessionKey, new MsgUserPermitReq() );
    }

    @Override
    public boolean msgGroupAdd( String nick, String groupname ) {
        return msgFetcher.msgGroupAdd( nick, groupname, new MsgGroupAddReq() );
    }

    @Override
    public VasOrderSearchResponse vasOrderSearch( VasOrderSearchReq req ) {
        return vasOrderSearchFetcher.fetch( req, 0, 2 );
    }

    @Override
    public ClouddataMbpStatusGetResponse mbpStatusGet( GetCloudDataStatusReq req ) {
        return cloudDataStatusFetcher.mbpStatusGet( req, 0, 2 );
    }

    @Override
    public List<ItemProp> getItemProps( GetItemPropsReq req ) {
        return itemPropsFetcher.fetch( req, 3 );
    }

    @Override
    public String generateSaleLink( GenerateSaleLinkReq request ) {
        return saleLinkGenerator.generate( request, 3 );
    }

    @Override
    public List<User> getUsers( GetUsersReq req ) {
        return usersFetcher.fetch( req, 2 );
    }

    @Override
    public List<DeliveryTemplate> getDeliveryTemplates( String sessionKey, GetDeliveryTemplatesReq req ) {
        return deliveryTemplateFetcher.fetch( sessionKey, req, 2 );
    }

    @Override
    public ItemUpdateDelistingResponse updateItemDelisting( UpdateDelistingReq req ) throws ApiException {
        return itemDelistingFetcher.update( req, 0, 2 );
    }

    @Override
    public ItemUpdateListingResponse updateItemListing( UpdateListingReq req ) throws ApiException {
        return itemListingFetcher.update( req, 0, 2 );
    }

    @Override
    public ItemSkuUpdateResponse updateItemSku( UpdateItemSkuReq req ) throws ApiException {
        return itemSkuFetcher.update( req, 0, 2 );
    }

    @Override
    public ItemDeleteResponse deleteItem( DeleteItemReq req ) throws ApiException {
        return itemDeleteFetcher.update( req, 0, 2 );
    }

    @Override
    public List<Warn> getItemProcessWarns( String sessionKey, GetItemProcessWarnsReq req ) {
        return itemProcessWarnsFetcher.fetchWarns( sessionKey, req, 0, 2 );
    }

    @Override
    public List<Punish> getItemProcessPunishes( String sessionKey, GetItemProcessPunishesReq req ) {
        return itemProcessPunishesFetcher.fetchPunishes( sessionKey, req, 0, 2 );
    }

    @Override
    public List<Shield> getItemProcessShields( String sessionKey, GetItemProcessShieldsReq req ) {
        return itemProcessShieldsFetcher.fetchShields( sessionKey, req, 0, 2 );
    }

    @Override
    public List<Advise> getItemProcessAdvises( String sessionKey, GetItemProcessAdvisesReq req ) {
        return itemProcessAdvisesFetcher.fetchAdvises( sessionKey, req, 0, 2 );
    }


    protected TaobaoClient getTaobaoClient() {
        if ( null == taobaoClient ) {
            synchronized ( this ) {
                if ( null == taobaoClient ) {
//                    taobaoClient = TaobaoClientProxy.createLoggedTaobaoClient(
//                            new DefaultTaobaoClient(
//                                    getClientConfig().getServerUrl(),
//                                    getClientConfig().getAppKey(),
//                                    getClientConfig().getAppSecret(),
//                                    getClientConfig().getFormat()
//                            )
//                    );
                    taobaoClient = new TaobaoClientWrapper(
                            new DefaultTaobaoClient(
                                    getClientConfig().getServerUrl(),
                                    getClientConfig().getAppKey(),
                                    getClientConfig().getAppSecret(),
                                    getClientConfig().getFormat()
                            )
                    );
                }
            }
        }
        return taobaoClient;
    }

    /**
     * 橱窗剩余数量
     *
     * @author luohui
     */
    private class ShopRemainShowcaseFetcher {

        ShopRemainshowcaseGetResponse fetch( String sessionKey, int retryTime, int maxTime ) throws ApiException {
            ShopRemainshowcaseGetResponse response;
            try {
                response =
                        new GetShopRemainShowcaseReq()
                                .taobaoClient( getTaobaoClient() )
                                .sessionKey( sessionKey )
                                .send();
            } catch ( ApiException e ) {
                if ( retryTime < maxTime ) {
                    return fetch( sessionKey, ++retryTime, maxTime );
                } else {
                    throw e;
                }
            }
            return response;
        }

        public ItemRecommendDeleteResponse itemRecommendDelete( Long itemId, String sessionKey, int retryTime, int maxTime ) throws ApiException {
            ItemRecommendDeleteResponse response;
            try {
                TaobaoClient client = getTaobaoClient();
                ItemRecommendDeleteRequest req = new ItemRecommendDeleteRequest();
                req.setNumIid( itemId );
                response = client.execute( req, sessionKey );
            } catch ( ApiException e ) {
                if ( retryTime < maxTime ) {
                    return itemRecommendDelete( itemId, sessionKey, ++retryTime, maxTime );
                } else {
                    throw e;
                }
            }
            return response;
        }

        public ItemRecommendAddResponse itemRecommendAdd( Long itemId, String sessionKey, int retryTime, int maxTime ) throws ApiException {
            ItemRecommendAddResponse response;
            try {
                TaobaoClient client = getTaobaoClient();
                ItemRecommendAddRequest req = new ItemRecommendAddRequest();
                req.setNumIid( itemId );
                response = client.execute( req, sessionKey );
            } catch ( ApiException e ) {
                if ( retryTime < maxTime ) {
                    return itemRecommendAdd( itemId, sessionKey, ++retryTime, maxTime );
                } else {
                    throw e;
                }
            }
            return response;
        }
    }

    private class OnSaleItemFetcher extends LimitFetchSupport {

        List<Item> fetchOnSaleItems( String sessionKey, GetOnSaleItemFields fields,
                                     int retryTime, final int maxTimes ) {
            List<Item> items;

            if ( retryTime >= maxTimes ) {
                return new ArrayList<>();
            }

            try {
                items = getSellerItems( sessionKey, fields );
            } catch ( ApiException e ) {
                items = fetchOnSaleItems( sessionKey, fields, ++retryTime, maxTimes );
            }

            return items;
        }

        List<Item> fetchOnSaleItems( String sessionKey, GetOnSaleItemReq req,
                                     int retryTime, final int maxTimes ) {
            List<Item> items;

            if ( retryTime >= maxTimes ) {
                return new ArrayList<>();
            }

            try {
                items = getSellerItems( sessionKey, req );
            } catch ( ApiException e ) {
                items = fetchOnSaleItems( sessionKey, req, ++retryTime, maxTimes );
            }

            return items;
        }

        Fragment<Item> fetchOnSaleItemsLimit( final String sessionKey, final GetOnSaleItemFields fields,
                                              int retryTime, final int maxTimes, final int begin, final int offset ) {
            Fragment<Item> fragment;

            if ( retryTime >= maxTimes ) {
                return null;
            }

            try {
                fragment = limitFetch( begin, offset, new RequestSender() {
                    private Long itemCount;

                    @Override
                    public List<Item> send( long pageNo, long pageSize ) throws ApiException {

                        ItemsOnsaleGetResponse resp = sellerItemsReq( sessionKey, fields )
                                .pageNo( pageNo ).pageSize( pageSize ).send();

                        if ( null == itemCount ) {
                            itemCount = resp.getTotalResults();
                        }
                        return null != resp ? resp.getItems() : null;
                    }

                    @Override
                    public Long itemTotalCount() {
                        return itemCount;
                    }

                } );
            } catch ( ApiException e ) {
                fragment = fetchOnSaleItemsLimit( sessionKey, fields, ++retryTime, maxTimes, begin, offset );
            }

            return fragment;
        }

        Long getOnSaleItemsCount( String sessionKey, int retryTime, final int maxTimes ) {
            if ( retryTime >= maxTimes ) {
                return 0L;
            }

            ItemsOnsaleGetResponse resp;
            try {
                resp = sellerItemsReq( sessionKey,
                        new GetOnSaleItemFields().num_iid() ).send();
            } catch ( ApiException e ) {
                return getOnSaleItemsCount( sessionKey, ++retryTime, maxTimes );
            }

            if ( null != resp ) {
                return resp.getTotalResults();
            } else {
                return 0L;
            }
        }

        private List<Item> getSellerItems( String sessionKey, GetOnSaleItemFields fields )
                throws ApiException {
            List<Item> items = new ArrayList<Item>();
            final long pageSize = 200;

            long pagesCount = Long.MAX_VALUE;
            for ( long pageNo = 1; pageNo <= pagesCount; pageNo++ ) {

                ItemsOnsaleGetResponse resp = sellerItemsReq( sessionKey, fields )
                        .pageNo( pageNo ).pageSize( pageSize ).send();

                List<Item> fetchedItems = resp.getItems();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getTotalResults();
                    if ( null != total ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 1L;
                    }
                }

            }
            return items;
        }

        private List<Item> getSellerItems( String sessionKey, GetOnSaleItemReq req )
                throws ApiException {
            List<Item> items = new ArrayList<Item>();
            final long pageSize = 200;

            long pagesCount = Long.MAX_VALUE;
            for ( long pageNo = 1; pageNo <= pagesCount; pageNo++ ) {

                ItemsOnsaleGetResponse resp = sellerItemsReq( sessionKey, req )
                        .pageNo( pageNo ).pageSize( pageSize ).send();

                List<Item> fetchedItems = resp.getItems();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getTotalResults();
                    if ( null != total ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 1L;
                    }
                }

            }
            return items;
        }

        private GetOnSaleItemReq sellerItemsReq( String sessionKey, GetOnSaleItemReq req ) {
            return req.sessionKey( sessionKey ).taobaoClient( getTaobaoClient() );
        }

        private GetOnSaleItemReq sellerItemsReq( String sessionKey, GetOnSaleItemFields fields ) {
            return new GetOnSaleItemReq().fields( fields )
                    .sessionKey( sessionKey ).taobaoClient( getTaobaoClient() );
        }

    }

    private class InventoryItemFetcher extends LimitFetchSupport {

        List<Item> fetchItems( String sessionKey, GetInventoryItemReq req,
                               GetInventoryItemFields fields, int retryTime, final int maxTimes ) {
            List<Item> items = null;
            try {
                items = getAllInventoryItems( sessionKey, req, fields );
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    items = fetchItems( sessionKey, req, fields, ++retryTime, maxTimes );
                }
            }

            return items;
        }

        Fragment<Item> fetchItemsLimit( final String sessionKey,final GetInventoryItemReq req, final GetInventoryItemFields fields,
                                        int begin, int offset, int retryTime, int maxTimes ) {
            Fragment<Item> fragment;

            if ( retryTime >= maxTimes ) {
                return null;
            }

            try {
                fragment = limitFetch( begin, offset, new RequestSender() {
                    private Long itemCount;

                    @Override
                    public List<Item> send( long pageNo, long pageSize ) throws ApiException {

                        ItemsInventoryGetResponse resp = inventoryItemReq( sessionKey, req, fields )
                                .pageNo( pageNo ).pageSize( pageSize ).send();

                        if ( null == itemCount ) {
                            itemCount = resp.getTotalResults();
                        }
                        return null != resp ? resp.getItems() : null;
                    }

                    @Override
                    public Long itemTotalCount() {
                        return itemCount;
                    }

                } );
            } catch ( ApiException e ) {
                fragment = fetchItemsLimit( sessionKey, req, fields, ++retryTime, maxTimes, begin, offset );
            }

            return fragment;
        }

        private List<Item> getAllInventoryItems( String sessionKey, GetInventoryItemReq req, GetInventoryItemFields fields ) throws ApiException {
            List<Item> items = new ArrayList<Item>();
            final long pageSize = 200;

            long pagesCount = Long.MAX_VALUE;
            for ( long pageNo = 1; pageNo <= pagesCount; pageNo++ ) {

                ItemsInventoryGetResponse resp = inventoryItemReq( sessionKey, req, fields )
                        .pageNo( pageNo ).pageSize( pageSize ).send();

                List<Item> fetchedItems = resp.getItems();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getTotalResults();
                    if ( null != total ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 0L;
                    }
                }
            }

            return items;
        }

        private GetInventoryItemReq inventoryItemReq( String sessionKey, GetInventoryItemReq req, GetInventoryItemFields fields ) {
            if ( null != req ) {
                return req.sessionKey( sessionKey ).taobaoClient( getTaobaoClient() )
                        .fields( fields );
            } else {
                return new GetInventoryItemReq().sessionKey( sessionKey ).taobaoClient( getTaobaoClient() )
                        .fields( fields );
            }
        }

    }

    private class ItemFetcher {

        Item fetchItem( String sessionKey, Long itemId, GetItemInfoFields fields,
                        int retryTime, int maxTimes ) {
            return itemGet( sessionKey, itemId, fields, retryTime, maxTimes );
        }

        private Item itemGet( String sessionKey, Long itemId, GetItemInfoFields fields,
                              int retryTime, final int maxTimes ) {
            Item item;

            if ( retryTime >= maxTimes ) {
                return null;
            }

            try {
                item = new GetItemInfoReq().sessionKey( sessionKey )
                        .taobaoClient( getTaobaoClient() )
                        .fields( fields ).numIid( itemId ).send().getItem();
            } catch ( ApiException e ) {
                item = itemGet( sessionKey, itemId, fields, ++retryTime, maxTimes );
            }

            return item;
        }
    }

    private class ShopInfoFetcher {

        private static final String SHOP_PIC_PATH_PREFIX = "http://logo.taobao.com/shop-logo";

        Shop fetch( String sessionKey, String nick, GetShopInfoFields fields, int retryTime, int maxTime ) {
            Shop shop = null;
            try {
                shop = new GetShopInfoReq()
                        .sessionKey( sessionKey )
                        .taobaoClient( getTaobaoClient() )
                        .fields( fields ).nick( nick ).send().getShop();
            } catch ( ApiException e ) {
                if ( retryTime < maxTime ) {
                    return fetch( sessionKey, nick, fields, ++retryTime, maxTime );
                }
            }

            if ( null != shop ) {
                String picPath = shop.getPicPath();
                if ( null != picPath && picPath.length() > 0 ) {
                    shop.setPicPath( SHOP_PIC_PATH_PREFIX + picPath );
                }
            }

            return shop;
        }

    }

    private class VasSubscribeGetFetcher {

        List<ArticleUserSubscribe> fetch( GetVasSubscribeReq req, int retryTime, int maxTime ) {
            List<ArticleUserSubscribe> articleUserSubscribe = null;
            try {
                VasSubscribeGetResponse vasSubscribeGetResponse = req.taobaoClient( getTaobaoClient() ).send();
                articleUserSubscribe = vasSubscribeGetResponse.getArticleUserSubscribes();
            } catch ( ApiException e ) {
                if ( retryTime < maxTime ) {
                    return fetch( req, ++retryTime, maxTime );
                }
            }
            return articleUserSubscribe;
        }

    }

    private class VasOrderSearchFetcher {

        VasOrderSearchResponse fetch( VasOrderSearchReq req, int retryTime, int maxTime ) {
            VasOrderSearchResponse vasOrderSearchResponse = null;
            try {
                vasOrderSearchResponse = req.taobaoClient( getTaobaoClient() ).send();
            } catch ( ApiException e ) {
                if ( retryTime < maxTime ) {
                    return fetch( req, ++retryTime, maxTime );
                }
            }
            return vasOrderSearchResponse;
        }

    }

    private abstract static class LimitFetchSupport {

        private static final int MAX_PAGE_SIZE = 200;

        interface RequestSender {

            public List<Item> send( long pageNo, long pageSize ) throws ApiException;

            ;

            public Long itemTotalCount();

        }

        protected Fragment<Item> limitFetch( final int begin, final int offset,
                                             RequestSender requestSender ) throws ApiException {

            if ( null == requestSender ) {
                return null;
            }

            List<Item> items = new ArrayList<Item>();
            final long pageSize = MAX_PAGE_SIZE;
            final long beginPageNo = begin > 0 ? ( begin / pageSize ) : 1;
            final long pageLimit = ( begin + offset ) / pageSize + 1;

            Long totalSize = null;
            for ( long pageNo = beginPageNo; pageNo <= pageLimit; pageNo++ ) {

                List<Item> fetchedItems = requestSender.send( pageNo, pageSize );

                if ( null == totalSize ) {
                    totalSize = requestSender.itemTotalCount();
                }

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

            }

            long sliceBegin = begin - ( beginPageNo - 1 ) * pageSize;
            long sliceOffset = offset;

            items = SliceUtil.doSlice( items, (int) sliceBegin, (int) sliceOffset );
            Fragment<Item> fragment = new Fragment<Item>();
            fragment.setContent( items );
            fragment.setTotalSize( null != totalSize ? totalSize.intValue() : 0 );
            fragment.generateIndexes( begin, offset );

            return fragment;
        }

    }

    private class ItemsFetcher extends LimitFetchSupport {

        List<Item> fetchItems( String sessionKey, String nick, GetItemsFields fields,
                               int retryTime, final int maxTimes ) {
            return itemsGet( sessionKey, nick, null, fields, retryTime, maxTimes );
        }

        List<Item> fetchItemsByCat( String sessionKey, Long cid, GetItemsFields fields,
                                    Integer limit, int retryTime, final int maxTimes ) {
            limit = ( null != limit && limit <= 200 ) ? limit : 200;

            List<Item> items = null;
            try {
                items = getItemsReq( sessionKey, null, fields ).
                        cid( cid ).pageNo( 0L ).pageSize( limit.longValue() ).send().getItems();
            } catch ( ApiException e ) {
                if ( retryTime < maxTimes ) {
                    items = fetchItemsByCat( sessionKey, cid, fields, limit, ++retryTime, maxTimes );
                }
            }

            return items;
        }

        Fragment<Item> fetchItemsLimit( final String sessionKey, final String nick, final GetItemsFields fields,
                                        int retryTime, final int maxTime, final int begin, final int offset ) {
            Fragment<Item> fragment = null;
            try {
                fragment = limitFetch( begin, offset, new RequestSender() {

                    private Long itemCount;

                    @Override
                    public List<Item> send( long pageNo, long pageSize ) throws ApiException {
                        ItemsGetResponse resp = getItemsReq( sessionKey, null, fields )
                                .addNick( nick ).pageNo( pageNo ).pageSize( pageSize ).send();

                        if ( null == itemCount ) {
                            itemCount = resp.getTotalResults();
                        }

                        return null != resp ? resp.getItems() : null;
                    }

                    @Override
                    public Long itemTotalCount() {
                        return itemCount;
                    }

                } );

            } catch ( ApiException e ) {
                if ( retryTime < maxTime ) {
                    fragment = fetchItemsLimit( sessionKey, nick, fields,
                            ++retryTime, maxTime, begin, offset );
                }
            }

            return fragment;
        }


        List<Item> searchItems( String sessionKey, String q, GetItemsFields fields,
                                int retryTime, final int maxTimes, final int begin, final int offset ) {
            List<Item> items;

            if ( retryTime >= maxTimes ) {
                return new ArrayList<>();
            }

            try {
                items = doSearchItems( sessionKey, q, fields, begin, offset );
            } catch ( ApiException e ) {
                items = searchItems( sessionKey, q, fields, ++retryTime, maxTimes, begin, offset );
            }

            return items;
        }

        List<Item> searchItemsByPopularity( String sessionKey, GetItemsFields fields, long cid, String order, String props, int limit ) {
            try {
                return getItemsByPopularity( sessionKey, null, fields, cid, order, props, limit );
            } catch ( ApiException e ) {
            }
            return null;
        }

        private List<Item> doSearchItems( String sessionKey, String q, GetItemsFields fields,
                                          final int begin, final int offset ) throws ApiException {
            List<Item> items = new ArrayList<Item>();
            final long pageSize = 200;

            long pagesCount = Long.MAX_VALUE;
            long pageNo = 1;
            if ( begin > 0 ) {
                pageNo = ( begin - 1 ) / pageSize;
            }
            pageNo = 0 == pageNo ? 1 : pageNo;

            int end = begin + offset;
            long pageLimit = end / pageSize + 1;
            if ( end > pageSize && end % pageSize > 0 ) {
                pageLimit++;
            }

            for (; pageNo <= pagesCount && pageNo <= pageLimit; pageNo++ ) {

                ItemsGetResponse resp = getItemsReq( sessionKey, q, fields )
                        .pageSize( pageSize ).send();

                List<Item> fetchedItems = resp.getItems();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getTotalResults();
                    if ( null != total && total > 0 ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 1L;
                    }
                }

            }

            return items;
        }

        private List<Item> itemsGet( String sessionKey, String nick, String q, GetItemsFields fields,
                                     int retryTime, final int maxTimes ) {
            List<Item> items;

            if ( retryTime >= maxTimes ) {
                return new ArrayList<>();
            }

            try {
                items = getItemsOfSeller( sessionKey, nick, q, fields );
            } catch ( ApiException e ) {
                items = itemsGet( sessionKey, nick, q, fields, ++retryTime, maxTimes );
            }

            return items;
        }

        private List<Item> getItemsOfSeller( String sessionKey, String nick, String q, GetItemsFields fields )
                throws ApiException {
            List<Item> items = new ArrayList<Item>();
            final long pageSize = 200;

            long pagesCount = Long.MAX_VALUE;
            for ( long pageNo = 1; pageNo <= pagesCount; pageNo++ ) {

                ItemsGetResponse resp = getItemsReq( sessionKey, q, fields )
                        .addNick( nick ).pageSize( pageSize ).send();

                List<Item> fetchedItems = resp.getItems();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getTotalResults();
                    if ( null != total ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 1L;
                    }
                }

            }

            return items;
        }

        private List<Item> getItemsByPopularity( String sessionKey, String q, GetItemsFields fields, Long cid, String order, String props, long pageSize )
                throws ApiException {
            ItemsGetResponse resp = getItemsReq( sessionKey, q, fields ).cid( cid ).pageSize( pageSize ).orderBy( order ).props( props ).send();
            return resp.getItems();
        }

        private GetItemsReq getItemsReq( String sessionKey, String q, GetItemsFields fields ) {
            return new GetItemsReq().q( q ).fields( fields ).sessionKey( sessionKey )
                    .taobaoClient( getTaobaoClient() );
        }

    }

    class SellerCatsFetcher {

        List<SellerCat> fetchSellerCats( String sessionKey, String nick,
                                         int retryTime, final int maxTimes ) {
            List<SellerCat> cats;

            if ( retryTime >= maxTimes ) {
                return null;
            }

            try {
                cats = getCats( sessionKey, nick );
            } catch ( ApiException e ) {
                cats = fetchSellerCats( sessionKey, nick, ++retryTime, maxTimes );
            }

            return cats;
        }

        private List<SellerCat> getCats( String sessionKey, String nick ) throws ApiException {
            return new GetSellerCatsReq()
                    .sessionKey( sessionKey ).nick( nick )
                    .taobaoClient( getTaobaoClient() ).send().getSellerCats();
        }

    }

    class ItemUpdater {

        ItemUpdateResponse update( UpdateItemReq req, int retryTime, final int maxTimes ) {
            try {
                return doUpdate( req, retryTime, maxTimes );
            } catch ( ApiException e ) {
            }
            return null;
        }

        ItemUpdateResponse updateNoExcepHandle( UpdateItemReq req, int retryTime, final int maxTimes ) throws ApiException {
            return doUpdate( req, retryTime, maxTimes );
        }

        ItemUpdateResponse doUpdate( UpdateItemReq req, int retryTime, final int maxTimes ) throws ApiException {
            try {
                return req.taobaoClient( getTaobaoClient() ).send();
            } catch ( ApiException e ) {
                if ( retryTime < maxTimes ) {
                    return doUpdate( req, retryTime, maxTimes );
                } else {
                    throw e;
                }
            }
        }
    }

    class CloudDataFetcher {

        ClouddataMbpDataGetResponse mbpGet( GetCloudDataReq req, int retryTime, int maxTimes ) {
            return mbpDateGet( req, retryTime, maxTimes );
        }

        private ClouddataMbpDataGetResponse mbpDateGet( GetCloudDataReq req, int retryTime, int maxTimes ) {
            try {
                return req.taobaoClient( getTaobaoClient() ).send();
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    return mbpDateGet( req, ++retryTime, maxTimes );
                } else {
                    return null;
                }
            }
        }

    }

    class CloudDataStatusFetcher {

        private ClouddataMbpStatusGetResponse mbpStatusGet( GetCloudDataStatusReq req, int retryTime, int maxTimes ) {
            try {
                return req.taobaoClient( getTaobaoClient() ).send();
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    return mbpStatusGet( req, ++retryTime, maxTimes );
                } else {
                    return null;
                }
            }
        }

    }

    class ItemsListFetcher {

        List<Item> fetch( String sessionKey, Set<String> itemIds, GetItemsListFields fields,
                          int retryTime, final int maxTimes ) {
            List<Item> items = null;
            try {
                items = new GetItemsListReq().taobaoClient( getTaobaoClient() )
                        .sessionKey( sessionKey ).addNumIids( itemIds )
                        .fields( fields ).send().getItems();
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    items = fetch( sessionKey, itemIds, fields, ++retryTime, maxTimes );
                }
            }

            return items;
        }

    }

    class ItemCatsFetcher {

        List<ItemCat> fetch( String sessionKey, GetItemCatsReq req, int retryTime, final int maxTimes ) {
            List<ItemCat> itemCats = null;
            try {
                itemCats = req.taobaoClient( getTaobaoClient() ).sessionKey( sessionKey )
                        .send().getItemCats();
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    itemCats = fetch( sessionKey, req, ++retryTime, maxTimes );
                }
            }

            return itemCats;
        }
    }


    class SellerFetcher {

        User fetch( String sessionKey, GetSellerReq req, int retryTime, final int maxTimes ) {
            User user = null;
            try {
                user = req.taobaoClient( getTaobaoClient() ).sessionKey( sessionKey )
                        .send().getUser();
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    user = fetch( sessionKey, req, ++retryTime, maxTimes );
                }
            }

            return user;
        }
    }

    /**
     * @author kane 品牌词
     */
    class BrandFetcher {
        ItempropsGetResponse fetch( Long cid, GetBrandInfoFields fields ) {
            ItempropsGetResponse response = null;
            GetBrandInfoReq req = new GetBrandInfoReq().fields( fields );
            req.setCid( cid );
            try {
                response = req.taobaoClient( getTaobaoClient() ).send();
            } catch ( Exception e ) {
            }
            return response;
        }
    }

    class JushitaJdpUserAdder {

        Boolean add( String sessionKey, String rdsName, int retryTime, final int maxTimes ) {
            try {
                return new AddJushitaJdpUserReq().rdsName( rdsName ).taobaoClient( getTaobaoClient() )
                        .sessionKey( sessionKey ).send().getIsSuccess();
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    return add( sessionKey, rdsName, ++retryTime, maxTimes );
                }
            }
            return null;
        }

    }

    class CloudDataFlowbacker {

        ClouddataMbpDataFlowbackResponse flowback( String sessionKey,
                                                   String tableName,
                                                   String data,
                                                   int retryTime,
                                                   final int maxTimes ) {
            try {
                return new FlowbackCloudDataReq().tableName( tableName )
                        .data( data ).taobaoClient( getTaobaoClient() ).sessionKey( sessionKey ).send();
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    return flowback( sessionKey, tableName, data, ++retryTime, maxTimes );
                }
            }
            return null;
        }

    }

    class MsgFetcher {
        boolean permitUserOnMsg( String sessionKey, MsgUserPermitReq req ) {
            TmcUserPermitResponse response;
            try {
                response = req.taobaoClient( getTaobaoClient() )
                        .sessionKey( sessionKey ).send();
                if ( null != response ) {
                    return response.getIsSuccess();
                }
            } catch ( Exception e ) {
            }
            return false;
        }

        boolean msgGroupAdd( String nick, String groupname, MsgGroupAddReq req ) {
            TmcGroupAddResponse response;
            try {
                response = req.setNick( nick ).setGroupname( groupname )
                        .taobaoClient( getTaobaoClient() ).send();
                return response.isSuccess();
            } catch ( Exception e ) {
            }
            return false;
        }
    }

    class ItemPropsFetcher {

        List<ItemProp> fetch( GetItemPropsReq req, final int retryOnFailure ) {
            ItempropsGetResponse resp = null;
            int tryTime = 0;
            boolean success;
            do {
                try {
                    resp = req.taobaoClient( getTaobaoClient() ).send();
                    success = resp.isSuccess();
                } catch ( ApiException e ) {
                    success = false;
                    //handled
                }
            } while ( !success && ++tryTime < retryOnFailure );
            return success ? resp.getItemProps() : null;
        }

    }

    /**
     * 生成服务平台营销链接
     *
     * @date 2014/09/23
     */
    class SaleLinkGenerator {
        String generate( GenerateSaleLinkReq req, final int retryOnFailure ) {
            FuwuSaleLinkGenResponse resp = null;
            int tryTime = 0;
            boolean success;
            do {
                try {
                    resp = req.taobaoClient( getTaobaoClient() ).send();
                    success = resp.isSuccess();
                } catch ( ApiException e ) {
                    success = false;
                }
            } while ( !success && ++tryTime < retryOnFailure );

            return success ? resp.getUrl() : null;
        }
    }

    class UsersFetcher {

        List<User> fetch( GetUsersReq req, final int retryOnFailure ) {
            UsersGetResponse resp = null;
            int tryTime = 0;
            boolean success;
            do {
                try {
                    resp = req.taobaoClient( getTaobaoClient() ).send();
                    success = resp.isSuccess();
                } catch ( ApiException e ) {
                    success = false;
                }
            } while ( !success && ++tryTime < retryOnFailure );

            return success ? resp.getUsers() : null;
        }

    }

    class DeliveryTemplateFetcher {

        List<DeliveryTemplate> fetch( String sessionKey, GetDeliveryTemplatesReq req, final int retryOnFailure ) {
            DeliveryTemplatesGetResponse resp = null;
            int tryTime = 0;
            boolean success;
            do {
                try {
                    resp = req.sessionKey( sessionKey ).taobaoClient( getTaobaoClient() ).send();
                    success = resp.isSuccess();
                } catch ( ApiException e ) {
                    success = false;
                }
            } while ( !success && ++tryTime < retryOnFailure );

            return success ? resp.getDeliveryTemplates() : null;
        }

    }

    class ItemDelistingFetcher{

        ItemUpdateDelistingResponse update( UpdateDelistingReq req, int retryTime, final int maxTimes ) throws ApiException {
            return doUpdate( req, retryTime, maxTimes );
        }

        ItemUpdateDelistingResponse doUpdate( UpdateDelistingReq req, int retryTime, final int maxTimes ) throws ApiException {
            try {
                return req.taobaoClient( getTaobaoClient() ).send();
            } catch ( ApiException e ) {
                if ( retryTime < maxTimes ) {
                    return doUpdate( req, retryTime, maxTimes );
                } else {
                    throw e;
                }
            }
        }
    }
    class ItemListingFetcher{

        ItemUpdateListingResponse update( UpdateListingReq req, int retryTime, final int maxTimes ) throws ApiException {
            return doUpdate( req, retryTime, maxTimes );
        }

        ItemUpdateListingResponse doUpdate( UpdateListingReq req, int retryTime, final int maxTimes ) throws ApiException {
            try {
                return req.taobaoClient( getTaobaoClient() ).send();
            } catch ( ApiException e ) {
                if ( retryTime < maxTimes ) {
                    return doUpdate( req, retryTime, maxTimes );
                } else {
                    throw e;
                }
            }
        }
    }

    class ItemDeleteFetcher{

        ItemDeleteResponse update( DeleteItemReq req, int retryTime, final int maxTimes ) throws ApiException {
            return doUpdate( req, retryTime, maxTimes );
        }

        ItemDeleteResponse doUpdate( DeleteItemReq req, int retryTime, final int maxTimes ) throws ApiException {
            try {
                return req.taobaoClient( getTaobaoClient() ).send();
            } catch ( ApiException e ) {
                if ( retryTime < maxTimes ) {
                    return doUpdate( req, retryTime, maxTimes );
                } else {
                    throw e;
                }
            }
        }
    }

    class ItemSkuFetcher{

        ItemSkuUpdateResponse update( UpdateItemSkuReq req, int retryTime, final int maxTimes ) throws ApiException {
            return doUpdate( req, retryTime, maxTimes );
        }

        ItemSkuUpdateResponse doUpdate( UpdateItemSkuReq req, int retryTime, final int maxTimes ) throws ApiException {
            try {
                return req.taobaoClient( getTaobaoClient() ).send();
            } catch ( ApiException e ) {
                if ( retryTime < maxTimes ) {
                    return doUpdate( req, retryTime, maxTimes );
                } else {
                    throw e;
                }
            }
        }
    }

    class ItemProcessWarnsFetcher{

        List<Warn> fetchWarns( String sessionKey,
                               GetItemProcessWarnsReq req, int retryTime, final int maxTimes ) {
            List<Warn> items = null;
            try {
                items = getAllWarns( sessionKey, req );
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    items = fetchWarns( sessionKey, req, ++retryTime, maxTimes );
                }
            }

            return items;
        }

        private List<Warn> getAllWarns( String sessionKey, GetItemProcessWarnsReq req )
                throws ApiException {
            List<Warn> items = new ArrayList<>();
            final long pageSize = 100;

            long pagesCount = Long.MAX_VALUE;
            for ( long pageNo = 1; pageNo <= pagesCount; pageNo++ ) {

                ItemProcessWarnsSearchResponse resp = req.sessionKey( sessionKey ).taobaoClient( getTaobaoClient() ).send();

                List<Warn> fetchedItems = resp.getWarnList();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getAllNum();
                    if ( null != total ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 1L;
                    }
                }

            }
            return items;
        }

    }

    class ItemProcessPunishesFetcher{

        List<Punish> fetchPunishes( String sessionKey,
                                    GetItemProcessPunishesReq req, int retryTime, final int maxTimes ) {
            List<Punish> items = null;
            try {
                items = getAllPunishes( sessionKey, req );
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    items = fetchPunishes( sessionKey, req, ++retryTime, maxTimes );
                }
            }

            return items;
        }

        private List<Punish> getAllPunishes( String sessionKey, GetItemProcessPunishesReq req )
                throws ApiException {
            List<Punish> items = new ArrayList<>();
            final long pageSize = 100;

            long pagesCount = Long.MAX_VALUE;
            for ( long pageNo = 1; pageNo <= pagesCount; pageNo++ ) {

                ItemProcessPunishesSearchResponse resp = req.sessionKey( sessionKey ).taobaoClient( getTaobaoClient() ).send();

                List<Punish> fetchedItems = resp.getPunishList();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getAllNum();
                    if ( null != total ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 1L;
                    }
                }

            }
            return items;
        }

    }

    class ItemProcessShieldsFetcher{

        List<Shield> fetchShields( String sessionKey,
                                   GetItemProcessShieldsReq req, int retryTime, final int maxTimes ) {
            List<Shield> items = null;
            try {
                items = getAllShields( sessionKey, req );
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    items = fetchShields( sessionKey, req, ++retryTime, maxTimes );
                }
            }

            return items;
        }

        private List<Shield> getAllShields( String sessionKey, GetItemProcessShieldsReq req )
                throws ApiException {
            List<Shield> items = new ArrayList<>();
            final long pageSize = 100;

            long pagesCount = Long.MAX_VALUE;
            for ( long pageNo = 1; pageNo <= pagesCount; pageNo++ ) {

                ItemProcessShieldsSearchResponse resp = req.sessionKey( sessionKey ).taobaoClient( getTaobaoClient() ).send();

                List<Shield> fetchedItems = resp.getShieldList();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getAllNum();
                    if ( null != total ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 1L;
                    }
                }

            }
            return items;
        }

    }
    class ItemProcessAdvisesFetcher{

        List<Advise> fetchAdvises( String sessionKey,
                                   GetItemProcessAdvisesReq req, int retryTime, final int maxTimes ) {
            List<Advise> items = null;
            try {
                items = getAllAdvises( sessionKey, req );
            } catch ( ApiException e ) {
                if ( retryTime <= maxTimes ) {
                    items = fetchAdvises( sessionKey, req, ++retryTime, maxTimes );
                }
            }

            return items;
        }

        private List<Advise> getAllAdvises( String sessionKey, GetItemProcessAdvisesReq req )
                throws ApiException {
            List<Advise> items = new ArrayList<>();
            final long pageSize = 100;

            long pagesCount = Long.MAX_VALUE;
            for ( long pageNo = 1; pageNo <= pagesCount; pageNo++ ) {

                ItemProcessAdvisesSearchResponse resp = req.sessionKey( sessionKey ).taobaoClient( getTaobaoClient() ).send();

                List<Advise> fetchedItems = resp.getAdviseList();

                if ( null != fetchedItems && fetchedItems.size() > 0 ) {
                    items.addAll( fetchedItems );
                }

                if ( 1 == pageNo ) {
                    Long total = resp.getAllNum();
                    if ( null != total ) {
                        pagesCount = (int) ( ( total - 1 ) / pageSize ) + 1;
                    } else {
                        pagesCount = 1L;
                    }
                }

            }
            return items;
        }

    }
}
